/* global RoomPosition RIGHT LEFT TOP BOTTOM */

import {ENEMY_STRENGTH_NONE} from 'room-defense';
import {getDangerMatrix} from 'utils/cost-matrix';

declare global {
	interface CreepMemory {
		role?: string;
		singleRoom?: string;
		go?: any;
	}

	interface CreepHeapMemory {
		suicideSpawn: Id<StructureSpawn>;
	}

	interface PowerCreepMemory {
		role: string;
		singleRoom?: string;
		go?: any;
	}
}

export default class Role {
	throttleAt: number;
	stopAt: number;

	/**
	 * Base class for creep roles.
	 * @constructor
	 */
	constructor() {
		this.throttleAt = 8000;
		this.stopAt = 2000;
	}

	run(creep: Creep | PowerCreep) {
		throw new Error('Implementation missing.');
	}

	preRun(creep: Creep | PowerCreep): boolean {
		if (this.containSingleRoomCreep(creep)) return false;

		if (creep instanceof Creep && creep.room.boostManager?.overrideCreepLogic(creep)) {
			return false;
		}

		return true;
	}

	/**
	 * Ensures that creeps which are restricted to a single room stay there.
	 *
	 * @param {Creep} creep
	 *   The creep to run logic for.
	 *
	 * @return {boolean}
	 *   True if creep is busy getting back to its room.
	 */
	containSingleRoomCreep(creep: Creep | PowerCreep): boolean {
		if (!creep.memory.singleRoom) return false;

		if (creep.pos.roomName === creep.memory.singleRoom) {
			let stuck = true;
			if (creep.pos.x === 0) {
				creep.move(RIGHT);
			}
			else if (creep.pos.y === 0) {
				creep.move(BOTTOM);
			}
			else if (creep.pos.x === 49) {
				creep.move(LEFT);
			}
			else if (creep.pos.y === 49) {
				creep.move(TOP);
			}
			else {
				stuck = false;
			}

			if (stuck) {
				creep.say('unstuck!');
				delete creep.memory.go;
				creep.clearCachedPath();
				return true;
			}
		}
		else {
			creep.whenInRange(10, new RoomPosition(25, 25, creep.memory.singleRoom), () => {});
			return true;
		}

		return false;
	}

	performRecycle(creep: Creep) {
		// Return home and suicide.
		if (!creep.heapMemory.suicideSpawn) {
			const spawn = creep.pos.findClosestByPath(FIND_MY_SPAWNS);
			creep.heapMemory.suicideSpawn = spawn?.id;

			if (!spawn) {
				creep.suicide();
				return;
			}
		}

		if (creep.heapMemory.suicideSpawn) {
			const spawn = Game.getObjectById(creep.heapMemory.suicideSpawn);
			if (spawn) {
				creep.whenInRange(1, spawn, () => {
					spawn.recycleCreep(creep);
				});
			}
			else {
				delete creep.heapMemory.suicideSpawn;
			}
		}
	}

	isSafePosition(creep: Creep | PowerCreep, pos: RoomPosition): boolean {
		if (!creep.room.isMine()) return true;
		if (creep.room.defense.getEnemyStrength() === ENEMY_STRENGTH_NONE) return true;

		const matrix = getDangerMatrix(creep.room.name);
		if (matrix.get(pos.x, pos.y) > 0) return false;

		return true;
	}
}
